package com.chipcoo.web.utils;

import com.chipcoo.utils.BeanUtils;
import org.springframework.http.MediaType;
import org.springframework.util.CollectionUtils;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

public final class MediaTypeUtils {
    public final static String HTTP_SERVLET_REQUEST_MEDIA_TYPES = "HTTP_SERVLET_REQUEST_MEDIA_TYPES";
    public static List<MediaType> getAcceptableMediaTypes(ServletRequest request){
        ContentNegotiationManager contentNegotiationManager = BeanUtils.getServletBean("contentNegotiationManager", ContentNegotiationManager.class);
        return getAcceptableMediaTypes(request,contentNegotiationManager);
    }
    public static List<MediaType> getAcceptableMediaTypes(ServletRequest request,ContentNegotiationManager contentNegotiationManager) {
        List<MediaType> acceptableMediaTypes=null;
        if(null!=contentNegotiationManager){
            try {
                if(request instanceof  HttpServletRequest) {
                    acceptableMediaTypes = contentNegotiationManager.resolveMediaTypes(new ServletWebRequest((HttpServletRequest)request));
                }
            }catch (Exception ex){
                ex.printStackTrace();
            }
        }
        return acceptableMediaTypes;
    }

    public static List<MediaType> getRequestSupportedMediaTypes(ServletRequest request,List<MediaType>  acceptableMediaTypes) {
        if(null!= request.getAttribute(MediaTypeUtils.HTTP_SERVLET_REQUEST_MEDIA_TYPES))
            return (List<MediaType>)request.getAttribute(MediaTypeUtils.HTTP_SERVLET_REQUEST_MEDIA_TYPES);
        else {
            if (null == acceptableMediaTypes || acceptableMediaTypes.isEmpty())
                acceptableMediaTypes = Collections.singletonList(MediaType.ALL);

            List<MediaType> producibleMediaTypes = getProducibleMediaTypes(request);
            Set<MediaType> compatibleMediaTypes = new LinkedHashSet<MediaType>();

            for (MediaType acceptable : acceptableMediaTypes) {
                for (MediaType producible : producibleMediaTypes) {
                    if (acceptable.isCompatibleWith(producible)) {
                        compatibleMediaTypes.add(getMostSpecificMediaType(acceptable, producible));
                    }
                }
            }
            List<MediaType> selectedMediaTypes = new ArrayList<MediaType>(compatibleMediaTypes);
            MediaType.sortBySpecificityAndQuality(selectedMediaTypes);


            request.setAttribute(MediaTypeUtils.HTTP_SERVLET_REQUEST_MEDIA_TYPES,selectedMediaTypes);
            return selectedMediaTypes;

        }
    }

    /**
     * 获取系统支持的媒体类型
     * @param request
     * @return
     */
    private static List<MediaType> getProducibleMediaTypes(ServletRequest request) {
        Set<MediaType> mediaTypes = (Set<MediaType>)request.getAttribute(HandlerMapping.PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE);
        if (!CollectionUtils.isEmpty(mediaTypes)) {
            return new ArrayList<MediaType>(mediaTypes);
        }
        else {
            return Collections.singletonList(MediaType.ALL);
        }
    }

    /**
     * 判断媒体类型是否一致
     * @param acceptType
     * @param produceType
     * @return
     */
    private static MediaType getMostSpecificMediaType(MediaType acceptType, MediaType produceType) {
        produceType = produceType.copyQualityValue(acceptType);
        return (MediaType.SPECIFICITY_COMPARATOR.compare(acceptType, produceType) < 0 ? acceptType : produceType);
    }

    public static boolean isAjax(List<MediaType> acceptableMediaTypes){
        if(null==acceptableMediaTypes) return false;
        if(acceptableMediaTypes.size()>0){
            return  acceptableMediaTypes.get(0).isCompatibleWith(MediaType.APPLICATION_JSON);
        }
        return  false;
    }
    public  static  boolean isAjax(ServletRequest request){
        return isAjax(getAcceptableMediaTypes(request));
    }

    public  static  boolean isAjax(){
        return isAjax(WebUtils.getCurrentRequest());
    }
}
